package com.binarysoft.service.common.http;

import java.io.File;
import java.io.InputStream;
import java.net.URL;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.Hashtable;
import java.util.Map;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;

import org.mortbay.jetty.Connector;
import org.mortbay.jetty.Handler;
import org.mortbay.jetty.NCSARequestLog;
import org.mortbay.jetty.Server;
import org.mortbay.jetty.handler.ContextHandler;
import org.mortbay.jetty.handler.ContextHandlerCollection;
import org.mortbay.jetty.handler.HandlerCollection;
import org.mortbay.jetty.handler.RequestLogHandler;
import org.mortbay.jetty.nio.SelectChannelConnector;
import org.mortbay.jetty.security.SslSocketConnector;
import org.mortbay.thread.QueuedThreadPool;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

import common.framework.dsb.AbstractServiceBean;
import common.framework.dsb.annotation.DSBService;
import common.framework.dsb.service.ServiceContext;
import common.framework.log.Logger;

@DSBService(name = "DSB/HttpService", startup = true)
public class HttpServiceBean extends AbstractServiceBean implements HttpService {
	private Server server = null;
	private String logDir = "log";

	private Map<String, ContextHandler> uriMappiing = new Hashtable<String, ContextHandler>();

	@Override
	public void start(ServiceContext serviceContext) throws Exception {
		super.start(serviceContext);

		serviceContext.loadConfigProperties("http.properties");

		String httpPort = serviceContext.getProperty("http.port");
		String httpsPort = serviceContext.getProperty("https.port");
		String maxthreads = serviceContext.getProperty("threadpool.maxthreads");

		String keystoreFileName = serviceContext.getProperty("keystore.file.name");
		String keystorePassword = serviceContext.getProperty("keystore.pwd");
		String keyPassword = serviceContext.getProperty("key.pwd");

		String trustKeystoreFileName = serviceContext.getProperty("trust.keystore.file.name");
		String trustKeystorePassword = serviceContext.getProperty("trust.keystore.pwd");
		logDir = serviceContext.getProperty("http.log.dir");

		URL keystoreFileURL = serviceContext.getConfigFile(keystoreFileName);
		URL trustKeystoreFileURL = serviceContext.getConfigFile(trustKeystoreFileName);

		server = new Server();

		QueuedThreadPool threadPool = new QueuedThreadPool();
		threadPool.setMaxThreads(Integer.parseInt(maxthreads));
		server.setThreadPool(threadPool);

		SelectChannelConnector connector = new SelectChannelConnector();
		connector.setPort(Integer.parseInt(httpPort));
		connector.setMaxIdleTime(30000);
		connector.setConfidentialPort(Integer.parseInt(httpsPort));
		server.setConnectors(new Connector[] { connector });
		System.out.println(new Date() + " http started at address: " + httpPort);

		SslSocketConnector sslSocketConnector = new SslSocketConnector();
		sslSocketConnector.setPort(Integer.parseInt(httpsPort));
		sslSocketConnector.setKeystore(keystoreFileURL.getPath());
		Logger.log(Logger.LOW_LEVEL, keystoreFileURL.getPath());
		sslSocketConnector.setPassword(keystorePassword);
		sslSocketConnector.setKeyPassword(keyPassword);
		sslSocketConnector.setTruststore(trustKeystoreFileURL.getPath());
		Logger.log(Logger.LOW_LEVEL, trustKeystoreFileURL.getPath());
		sslSocketConnector.setTrustPassword(trustKeystorePassword);
		server.addConnector(sslSocketConnector);
		System.out.println(new Date() + " https started at address: " + httpsPort);

		ContextHandlerCollection contexts = new ContextHandlerCollection();

		Collection<HandlerConfig> configs = loadHttpServices("http-service.xml");
		Handler[] handlers = new Handler[configs.size()];
		int i = 0;
		for (HandlerConfig config : configs) {
			try {
				ContextHandler contextHandler = new ContextHandler();
				contextHandler.setDisplayName(config.getName());
				contextHandler.setContextPath(config.getUri());
				Handler handler = (Handler) Class.forName(config.getClassName()).newInstance();
				contextHandler.setHandler(handler);
				uriMappiing.put(config.getUri(), contextHandler);
				Logger.log(Logger.LOW_LEVEL, config.getName() + "=" + config.getUri());
				handlers[i++] = contextHandler;
			} catch (Exception e) {
				Logger.printStackTrace(Logger.FUNCTION_LEVEL, "init handler", e);
			}
		}

		contexts.setHandlers(handlers);

		NCSARequestLog requestLog = new NCSARequestLog(logDir + File.separator + "jetty-yyyy_mm_dd.log");
		requestLog.setExtended(false);
		RequestLogHandler requestLogHandler = new RequestLogHandler();
		requestLogHandler.setRequestLog(requestLog);
		requestLog.start();

		HandlerCollection handlersColl = new HandlerCollection();
		handlersColl.setHandlers(new Handler[] { contexts, requestLogHandler });

		server.setHandler(handlersColl);
		server.start();

	}

	@Override
	public void refresh() throws Exception {
	}

	@Override
	public void close() throws Exception {
		server.stop();
	}

	@Override
	public Collection<HandlerConfig> listHandler() throws Exception {
		Collection<HandlerConfig> result = new ArrayList<HandlerConfig>();
		Collection<ContextHandler> handlers = uriMappiing.values();
		for (ContextHandler handler : handlers) {
			HandlerConfig config = new HandlerConfig();
			config.setName(handler.getDisplayName());
			config.setUri(handler.getContextPath());
			config.setClassName(handler.getHandler().getClass().getName());
			result.add(config);
		}
		return result;
	}

	@Override
	public void addHandler(String contextPath, Handler handler) throws Exception {
		ContextHandler contextHandler = uriMappiing.get(contextPath);
		if (contextHandler == null) {
			throw new Exception("Context path:" + contextPath + " not configured!");
		}
		contextHandler.setHandler(handler);
	}

	private Collection<HandlerConfig> loadHttpServices(String configFile) throws Exception {

		Collection<HandlerConfig> result = new ArrayList<HandlerConfig>();
		DocumentBuilderFactory docBuildFactory = DocumentBuilderFactory.newInstance();
		DocumentBuilder docBuilder = docBuildFactory.newDocumentBuilder();
		InputStream inputStream = serviceContext.getConfigFile(configFile).openStream();
		Document doc = docBuilder.parse(inputStream);
		Element root = doc.getDocumentElement();
		NodeList handlers = root.getChildNodes();

		for (int i = 0; i < handlers.getLength(); i++) {
			Node handlerNode = handlers.item(i);
			if (!handlerNode.getNodeName().equalsIgnoreCase("handler")) {
				continue;
			}
			String handlerName = getAttribute(handlerNode, "name");
			String uri = getAttribute(handlerNode, "uri");
			String className = getAttribute(handlerNode, "class");

			if (isEmpty(uri) || isEmpty(className)) {
				continue;
			}
			HandlerConfig hConfig = new HandlerConfig();
			hConfig.setName(handlerName);
			hConfig.setUri(uri);
			hConfig.setClassName(className);
			result.add(hConfig);
		}// for
		inputStream.close();

		return result;
	}

	private String getAttribute(Node n, String name) {
		NamedNodeMap nnm = n.getAttributes();
		for (int k = 0; k < nnm.getLength(); k++) {
			String nodeName = nnm.item(k).getNodeName();
			String nodeVal = nnm.item(k).getNodeValue();
			if (name.equalsIgnoreCase(nodeName)) {
				return nodeVal;
			}
		}
		return null;
	}

	private boolean isEmpty(String s) {
		return s == null || s.trim().equalsIgnoreCase("");

	}

	public static void main(String[] args) {

		String a = "/abc/abc.htm";
		System.out.println(a.substring(1));

	}

}
